package com.techie.mdm.appbar.showcase.binding;

import org.jdesktop.beansbinding.*;
import org.springframework.binding.value.ValueModel;
import org.springframework.binding.value.support.PropertyChangeSupport;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * Adapts a Property to a ValueModel
 */
public class BeansBindingValueModelAdapter implements ValueModel, PropertyStateListener
{
    final Property        property;
    final Object          source;

    final PropertyChangeSupport pcs;

    public BeansBindingValueModelAdapter(Object source, Property property)
    {
        this.property = property;
        this.source = source;
        this.pcs = new PropertyChangeSupport(this);
        property.addPropertyStateListener(source, this);
    }

    public Object getValue()
    {
        return property.getValue(source);
    }

    public void setValue(Object newValue)
    {
        property.setValue(source, newValue);
    }

    public void setValueSilently(Object newValue, PropertyChangeListener listenerToSkip)
    {
        // todo - implement this?
    }

    public void addValueChangeListener(PropertyChangeListener listener)
    {
        pcs.addPropertyChangeListener(listener);
    }

    public void removeValueChangeListener(PropertyChangeListener listener)
    {
        pcs.removePropertyChangeListener(listener);
    }

    public void propertyStateChanged(PropertyStateEvent propertyStateEvent)
    {
        if (propertyStateEvent.getValueChanged())
        {
            PropertyChangeEvent evt = new PropertyChangeEvent(propertyStateEvent.getSourceObject(),
                    ValueModel.VALUE_PROPERTY,
                    propertyStateEvent.getOldValue(),
                    propertyStateEvent.getNewValue());
            pcs.firePropertyChange(evt);
        }
    }

    static public ValueModel[] buildValueModels(ValueModel source, String... propertyPaths)
    {
        Property base = BeanProperty.create("value");
        ValueModel[] models = new ValueModel[propertyPaths.length];
        for (int i = 0; i < propertyPaths.length; i++)
        {
            String propertyPath = propertyPaths[i];            
            models[i] = buildValueModel(source, base, propertyPath);
        }
        return models;
    }

    public static ValueModel buildValueModel(Object source, Property base, String propertyPath)
    {
        return buildValueModel(source, base, propertyPath, isEL(propertyPath));
    }

    private static ValueModel buildValueModel(Object source, Property base, String propertyPath, boolean el)
    {
        Property p = buildProperty(base, propertyPath, el);
        return propertyToValueModel(source, p);
    }

    private static ValueModel propertyToValueModel(Object source, Property prop)
    {
        return new BeansBindingValueModelAdapter(source, prop);
    }

    private static Property buildProperty(Property base, String propertyPath, boolean el)
    {
        return !el ? BeanProperty.create(base, propertyPath)
                : ELProperty.create(base, propertyPath);
    }

    private static boolean isEL(String propertyPath)
    {
        return propertyPath.contains("${");
    }

}
